#ifndef GATE_H
#define GATE_H

#ifndef HEAD_H
#include "../head.h"
#endif

namespace gate
{
const static int directionNums = 4;
enum GateDirection
{
    Gate_UP,Gate_RIGHT,Gate_DOWN,Gate_LEFT,Gate_NONE,//方向, 顺时针顺序
};
enum class GateType{
    NONE,ENTER,EXIST,//出入口
};
} // namespace gate

class Gate
{
public:
    Coordinate position; //位置 具体是相对还是绝对看使用情况
    gate::GateDirection direction;
    gate::GateType gatetype;
    inline Gate()
        :position(0,0),direction(gate::GateDirection::Gate_NONE),gatetype(gate::GateType::NONE){}
    inline Gate(Coordinate relative_pos, gate::GateDirection direction, gate::GateType gatetype)
        :position(relative_pos),direction(direction),gatetype(gatetype)  {}
    inline void turn90ClockWise(int t){ // 以0，0为中心
        t = t % 4;
        position.turn90ClockWise(t);
        direction = (gate::GateDirection)((direction + t) % 4);
    }
    virtual bool can_take(const Gate &g){
        return false;
    }
    virtual bool can_goto(const Gate &g){
        return false;
    }
    inline void moveBy(const Coordinate &co){
        this->position += co;
    }
    virtual inline bool operator==(const Gate &g){
        return this->gatetype == g.gatetype
            && this->direction == g.direction
               && this->position == g.position;
    }
};

class EnterGate:public Gate{
public:
    inline EnterGate(Coordinate relative_pos, gate::GateDirection direction):
        Gate(relative_pos, direction, gate::GateType::ENTER){}
    bool can_take(const Gate &g) override{
        if(g.gatetype != gate::GateType::EXIST) return false;
        if(std::abs(this->direction - g.direction) != 2) return false;
        Coordinate co = position;
        switch(direction){
        case gate::Gate_UP:
            co += Coordinate(0,-1);
            break;
        case gate::Gate_RIGHT:
            co += Coordinate(1,0);
            break;
        case gate::Gate_DOWN:
            co += Coordinate(0,1);
            break;
        case gate::Gate_LEFT:
            co += Coordinate(-1,0);
            break;
        default:
            break;
        }
        return co == g.position;
    }
};

class ExitGate:public Gate{
public:
    inline ExitGate(Coordinate relative_pos, gate::GateDirection direction):
        Gate(relative_pos, direction, gate::GateType::EXIST){}
    bool can_goto(const Gate &g) override{
        if(g.gatetype != gate::GateType::ENTER) return false;
        if(std::abs(this->direction - g.direction) != 2) return false;
        Coordinate co = position;
        switch(direction){
        case gate::Gate_UP:
            co += Coordinate(0,-1);
            break;
        case gate::Gate_RIGHT:
            co += Coordinate(1,0);
            break;
        case gate::Gate_DOWN:
            co += Coordinate(0,1);
            break;
        case gate::Gate_LEFT:
            co += Coordinate(-1,0);
            break;
        default:
            break;
        }
        return co == g.position;
    }
};

#endif // GATE_H
